package RemoteCommunication;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;

import DDNS.DDNS;
import Queue.Item;
import Queue.WriteQueue;
import DatabaseRemote.Authentication;
import Server.ConnectionHandler;
import Server.Server;

public class ClientInputCmdListener implements Runnable{
	private ForwardClientCmdToLocal[] forward = new ForwardClientCmdToLocal[100]; 
	private WriteQueue wq;
	private Item its;
	private Server server;
	private Authentication login;
	boolean test=false;
	private static AtomicBoolean updated = new AtomicBoolean(true);
	private ConcurrentHashMap commandQueue;
	private boolean hasConnections=false;
	private DDNS ddns = new DDNS();
	public ClientInputCmdListener(){//DDNS Created by zijie, modified by Zijie and Tarik
		this.its = new Item();
		this.server= new Server(5906,9999, 0, "/home/v4h4/git/keystore.jks", "password", "pwnage12","exit");
		Thread connectionListener = new Thread(server,"Server");
		connectionListener.start();
		this.wq = server.getTheQueue();
		ddns.updateIpWithDDNS();        
		try{
			Thread.currentThread().sleep(3000);//F�r att DDNS ska f� lite tid att uppdatera
		}catch(Exception ex){
			ex.printStackTrace();
		}
		login = new Authentication();
		System.out.println("Object av protokollet är skapade");
		RealtimeClientCommunication realtime = new RealtimeClientCommunication(server,wq);
		Thread thread = new Thread(realtime,"Realtime System");
		thread.start();
	}
	
	public void run(){
		cmdReceiver();
	}

	private void cmdReceiverOutPrints(Item item){
		System.out.println("\n\n\n\n||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||");
		if(item.getUser()!=null){
			System.out.println("item.getUser() == "+item.getUser());
		}
		if(item.getUser()==null){
			System.out.println("item.getUser() == null");							
		}
		System.out.println("item.getCmd() == "+item.getCmd());
		System.out.println("item.isAnswered == "+item.isAnswered());//its this
		System.out.println("||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\n\n\n\n");
	}
	
	public synchronized void cmdReceiver(){//@authors: created by Dino,Zijie,Tarik 
		try{
			commandQueue=wq.getMap();
			while(true){
				checkForUpdates();
				for(int i = 0; i<commandQueue.size(); i++) {
					Item item;
					if((item= (Item) commandQueue.get(i)).isAnswered() == false) {//here it has to be false,,because it is unanswerd then, right? yeah
						cmdReceiverOutPrints(item);
						checkForUpdates();
						establishConnectionBetweenRSAndLS(item, i);     //user!=null , getCmd.get(0)=="sendingIpAndPort", isAnserwed==false
						authenticationForUnauthorizedClients(item,i);   //user!=null , getCmd.get(0)=="login", isAnserwed==false
						forwardCmdToLocal(item,i); //How do you get true in a statement that needs false?
					}
					if(i==commandQueue.size()-1 && (item= (Item) commandQueue.get(i)).isAnswered() == false){
						  item.setReply("error_code 701 - igen �tg�rd lyckades att k�ras_");
			       }
				}  
				
			}
			
		}catch(Exception ex){
			ex.printStackTrace();		
		}
	}
	
	private void checkForUpdates(){
		if(wq.getHasAddedCommands()==true || wq.getMap().size()!=commandQueue.size()){//stop executing and update hasmap and sort it
			commandQueue=wq.getMap();
			wq.setHasAddedCommands(false);
		}
	}
	
	private synchronized void establishConnectionBetweenRSAndLS(Item item,int i){
		//here it will be errors when we run it
		if(item.getUser()==null && convertStringToArrayList(item.getCmd()).get(0).equals("SendingIpAndPort") && item.isAnswered()==false){//En LS server skapar kontakt mellan RS och LS
			   boolean lsFound=false;
			   test=true;
			   ArrayList ipAndPort=convertStringToArrayList(item.getCmd());
		       String ip=ipAndPort.get(1).toString();
		       int port=Integer.parseInt(ipAndPort.get(2).toString());
		       int houseId=Integer.parseInt(ipAndPort.get(ipAndPort.size()-1).toString());
		       try{//you can run it once if you want,,,sepideh can run the localserver if this is started WAit--ok
		    	   for(int q=0;q<forward.length;q++){
		    		   System.out.println("if(forward["+q+"]==null){");
		    		   //forward is an array of an classs i will show you it now
		    		   if(forward[q]==null && lsFound==false){//h�r skapas en server och lagras i en klass array
		    			   System.out.println("ForwardClientCmdToLocal remoteClient = new ForwardClientCmdToLocal("+ip+", "+port+","+houseId+");");	
		    			   ForwardClientCmdToLocal remoteClient = new ForwardClientCmdToLocal(ip, port,houseId);
		    			   System.out.println("forward[q]= remoteClient;");	
		    			   forward[q]= remoteClient;
		    			   
		    			   System.out.println("lsFound=true;");	
		    			   lsFound=true;
		    			   //counter++;
		    			   q=forward.length+1;
		    			   System.out.println("Done");
		    			   item.setUser("LS_"+houseId+"_");
		    			   item.setReply("SendingIpAndPort_Connection Accomplished_");	
		    			   //here in this metohed we will try to recive infomation from 
		    			   //localserver about its connection iformation such as port,ip,houseID
		    			   
		    			   //then we will create a connection by using a client in the previus
		    			   //classs i showed you, named: ForwardClientCmdToLocal 
		    	   		}
		    	   }
		    	   for(int r=0;r<forward.length;r++){
		    		   if(forward[r]==null){
		    			   System.out.println("forward["+r+"] == null");
		    		   }else{
		    			   System.out.println("forward["+r+"] == "+forward[r].getHouseId());
		    		   }
		    	   }
		       }catch(Exception ex){
    			   System.out.println("\n\nERROR couldn't create server in array\n\n");
    		   }
		       if(lsFound==false){
					  item.setReply("error_LS could not be created_code 901_");
		       }
		}
	}
	
	private void authenticationForUnauthorizedClients(Item item,int i){//n�r man loggas in f�r man sitt user id i item.getUser , id best�r av ssn_houseId_
		  if(item.isAnswered()==false && item.getUser()==null && item.getCmd().contains("authenticate")){
			  System.out.println("START - whole login process: "+0);
			  long runningTime=System.currentTimeMillis();
			  String authentication=login.authenticationResult(item.getCmd());
			  if(!authentication.contains("FAILD")){
				  boolean lsFound=false;
				  String command=item.getCmd();
				  int house_id=Integer.parseInt(convertStringToArrayList(authentication).get(1).toString());
				  for(int q=0;q<forward.length && lsFound==false;q++){
					  if(forward[q]!=null && forward[q].getHouseId()==house_id){
						  forward[q].sendCommand(command);
						  String result=forward[q].getCommand();
						  item.setUser(convertStringToArrayList(authentication).get(2).toString()+"_"+house_id+"_");//login
						  item.setUserPrio(0);
						  item.setReply(result);
						  lsFound=true;
						  System.out.println("login"+result);
						  System.out.println("Authentication == OK");
					  }
				  }
				  if(lsFound==false){
					  item.setReply("error_server not found_code 101_");
				  }
			  } else{
				  item.setReply("error_Authentication FAILD_");
			  }   
			  runningTime = System.currentTimeMillis()-runningTime;
			  System.out.println("END - whole login process: "+runningTime);
			  runningTime=0;
		  	}  
	}
	
	private boolean forwardCmdToLocal(Item item,int i){
		System.out.println("\ni=="+i+"\nitem.getUser() == "+item.getUser());
		System.out.println("item.getCmd() == "+item.getCmd());
		System.out.println("item.isAnswered() == "+item.isAnswered()+"\n\n");
		if(item.getUser()!=null && item.isAnswered()==false && !item.getCmd().contains("authenticate") && !item.getCmd().contains("SendingIpAndPort")){//u
		   try{
			   System.out.println("3.1");
			   boolean isFound=false;
			   int size=convertStringToArrayList(item.getUser()).size();
			   String command=item.getCmd();
			   String cmdResult=convertStringToArrayList(command).get(0).toString();
			   int houseId=Integer.parseInt(convertStringToArrayList(item.getUser()).get(size-1).toString());
			   String replay="error_server not found_code 101_";
			   for(int q=0;q<forward.length;q++){
				  if(forward[q]!=null){//utskrifter
					   System.out.println("\n\nforward["+q+"].getHouseId() == housId");
					   System.out.println(forward[q].getHouseId() +" == "+ houseId+"\n\n");
				  }//but,,with the old we could connect as i told you,,so now we can connect, one sec, I will test my code ok
				   if(forward[q]!=null && forward[q].getHouseId()==houseId){//kollar om housid i item.getUser �r lika med housid i server, sedan skickar
					   forward[q].sendCommand(command);
					   replay=forward[q].getCommand();
					   item.setReply(replay);
					   isFound=true;
					   System.out.println("FOUND\nnow isFound==true");
				   }
			   }
			   if(isFound==false){
				   item.setReply(replay);
				   System.out.println("lsFound==false");
			   }
		   }catch(Exception ex){
			   ex.printStackTrace();
		   }
		}
		return true;
	}
	
	private ArrayList convertStringToArrayList(String stringList) {
		ArrayList taskList = new ArrayList();
		int lastSeparator = -1;
		for (int i = 0; i < stringList.length(); i++) {
			if (stringList.charAt(i) == '_') {
				taskList.add(stringList.subSequence(lastSeparator + 1, i));
				lastSeparator = i;
			}
		}
		return taskList;
	}
	//Where does that message happen?wich message aok,,
	private boolean isMalawareCode(String command){
		String allowed="qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_!1234567890";
		int counter=0;
		for(int i=0;i<command.length();i++){
			for(int q=0;q<allowed.length();q++){
				if(command.charAt(i)==allowed.charAt(q)){
					counter++;
				}
			}
		}
		if(counter==command.length() && command.contains("!")){
			return false;
		}
		return true;
	}
	public boolean getHasConnections(){
		return this.hasConnections;
	}
		
}
